classdef LFSR < handle
% Linear Feed-Back Shift Register

properties
	Coefficients;
	InitialState;
	OutputCoefficients;
end % end of properties
properties (SetAccess = private)
	State;
	PreviousState;
	NumberOfStages;
end % end of properties
properties (SetAccess = private)
	BitMask_Generate;
end
properties (SetAccess = private, GetAccess = protected)
	BitMask_HMatrix;
end % end of properties

methods
	
	function obj = LFSR(Coefficients, varargin)
		if (nargin <= 0)
			error('Number of arguments must be larger than one')
		end	
		[m n] = size(Coefficients);
		if (m ~= 1)
			error('Coefficients must be a 1-D row integer array');	
		end
		obj.Coefficients = Coefficients;
		obj.NumberOfStages = max(obj.Coefficients);
		obj.BitMask_HMatrix = zeros(1, obj.NumberOfStages +1);
		CoefficientsHMatrix = obj.NumberOfStages - obj.Coefficients;
		obj.BitMask_HMatrix(CoefficientsHMatrix +1) = 1;
		if (nargin == 1) 
			obj.InitialState = ones(1, obj.NumberOfStages);
			obj.State = obj.InitialState;
			obj.BitMask_Generate = uint32(0);
			K = length(obj.Coefficients);
			k = 0;
			for i=1:K
				if (obj.Coefficients(i) ~= 0)
					%obj.BitMask_Generate = bitset(obj.BitMask_Generate, ...
					%														  obj.Coefficients(i));
					obj.BitMask_Generate = bitset(obj.BitMask_Generate, ...
							obj.NumberOfStages - obj.Coefficients(i) +1);
					k = k + 1;
				end
			end
			if (k ~= (K-1))
				error('Invalid LFSR coefficients, zero must be present')
			end
		end
	end

	function obj = set.Coefficients(obj, value)
		obj.Coefficients = value;
	end
	
	function obj = set.InitialState(obj, value)
		L = length(value);
		temp = uint32(0);
		for i=L:(-1):1		
			if (value(L -i +1) == 1)
				temp = bitset(temp, i); 
			end
		end	
		obj.InitialState = temp;
	end

	function out = Generate(obj, NumberOfChips)
		[m n] = size(NumberOfChips);
		if ((m ~= 1) || (n ~= 1) || (NumberOfChips <= 0))
			error('NumberOfChips must be an integer > 0');	
		end
		out = zeros(1, NumberOfChips);
		for i=1:NumberOfChips
			out(1, i) = obj.GenerateChip;
		end
	end

	function obj = Reset(obj)
		obj.State = obj.InitialState;
	end

	function out = GetHMatrix(obj, NumberOfChips)
		if ((NumberOfChips <= 0))
			error('NumberOfChips must be an integer > 0');	
		end
		out = zeros(NumberOfChips - obj.NumberOfStages, NumberOfChips);
		for i = 1:(NumberOfChips - obj.NumberOfStages)
			out(i, i:(i+obj.NumberOfStages)) = obj.BitMask_HMatrix;
		end
	end

end % end of methods

methods (Access = private)
	
	function out = GenerateChip(obj)
		if (isempty(obj.OutputCoefficients))
			out = bitget(obj.State, 1);
		else
			out = 0;
			for i=1:length(obj.OutputCoefficients)
				out = out + bitget(obj.State, obj.NumberOfStages - ...
																			obj.OutputCoefficients(i) +1);
			end
			out = mod(out, 2);
		end
		new_chip = LFSR.ParityCheck32(bitand(obj.State, obj.BitMask_Generate));
		obj.PreviousState = obj.State;
		obj.State = bitshift(obj.State, -1);
		obj.State = bitset(obj.State, obj.NumberOfStages, new_chip);
	end

end % end of private methods

methods (Static)
	function out = ParityCheck32(in)
		temp = bitxor(bitshift(in, -16), in);
		temp = bitxor(bitshift(temp, -8), temp);
		temp = bitxor(bitshift(temp, -4), temp);
		temp = bitxor(bitshift(temp, -2), temp);
		temp = bitxor(bitshift(temp, -1), temp);
		out = bitget(temp,1);
	end
end

end % end of class



